
function  makeStreamData(inData,Order,feature){
    var data = inData.data;
    anyfeature = feature;

    var typeInfo = inData.typelist;
    var x1,x2;
    var types = ["type1","type2","type0","type3","type4","type5","type6"];
    var minfeature = parseFloat(d3.min(data,function (d) {
        return d[feature];
    }));
    var maxfeature =parseFloat( d3.max(data,function (d) {
        return d[feature];
    }));
   scaleX = d3.scaleLinear().domain([minfeature,maxfeature]).range([0,200]);
    streamData = [];
    for(var a = 0;a <= 20; a=a+1)
    {
        tmp = {};
        tmp.feature =scaleX.invert(a*10);
        tmp.type1 = 0;
        tmp.type2 = 0;
        tmp.type0 = 0;
        tmp.type3 = 0;
        tmp.type4 = 0;
        tmp.type5 = 0;
        tmp.type6 = 0;
        streamData.push(tmp);
    }
    for(var i = 0;i<data.length;i++)
    {
        for(var j=0;j<streamData.length;j++)
        {
            if(parseFloat(data[i][feature])>=scaleX.invert(j*10) && parseFloat(data[i][feature])<scaleX.invert(j*10+10))
            {

                streamData[j]["type"+typeInfo[i]]++;

            }

        }
    }
    if(Order==0)
    {
        x1 = minfeature;
        x2 = inData.threshold;
    }
    else
    {
        x1 = inData.threshold;
        x2 = maxfeature;
    }
    x2 = parseFloat(x2);
    x1 = parseFloat(x1);
    stream ={};
    stream.data = streamData;
    stream.type = types;
    stream.x1 =parseFloat(x1.toFixed(0));
    stream.x2 =parseFloat(x2.toFixed(0));
    stream.text = inData.text;
    return stream;
}
function drawStreamChart(con,inData,splitValue,maxmistake,order){
    feature = splitValue.index;
    center = splitNode.center;
    stream = makeStreamData(inData,0,feature);
    var lineData = splitValue.mistakelist;
    lineData.sort(function (a,b){return d3.ascending(a[0],b[0])});
    var data = stream.data;
    var types = stream.type;

    /* ----------------------------配置参数------------------------  */
    const chart = new Chart();
    const config = {
        margins: {top: 38, left: 75, bottom: 15, right: 5},
        textColor: 'black',
        gridColor: 'gray',
        title: '基础河流图',
        animateDuration: 1000
    }

    chart.margins(config.margins);
    chart.width(300);
    chart.height(120)

    /* ----------------------------尺度转换------------------------  */
    chart.scaleX = d3.scaleLinear()
                    .domain([d3.min(data,function (d) {
                        return d.feature;
                    }),d3.max(data,function (d) {
                        return d.feature;})])
                    .range([0, chart.getBodyWidth()]);
    let dis = Math.floor(d3.max(data,function (d) {
                             tmp = 0;
                            for(type of types)
                                tmp+=d[type]
                            return tmp;
                        }))+1;
    chart.scaleY = d3.scaleLinear()
                    .domain([-dis/2,dis/2])
                    .range([chart.getBodyHeight(), 0])
    chart.lineScale= d3.scaleLinear()
                    .domain([0,maxmistake])
                    .range([chart.getBodyHeight(),0]);
    chart.stack = d3.stack()
                    .keys(types)
                    .order(d3.stackOrderInsideOut)
                    .offset(d3.stackOffsetSilhouette);

    /* ----------------------------渲染面------------------------  */
    var maxnum = chart.stack(data);
    var max = d3.max(maxnum);
    max = d3.max(max,(d)=>d[1]);
    max = chart.scaleY(max);
    var min = d3.min(maxnum);
    min = d3.min(min,(d)=>d[0]);
    min = chart.scaleY(min)-chart.scaleY(0);


    chart.renderOrder = function (){
        chart.svg().append("circle").attr("cx",20).attr("cy",60).attr("r",15).attr('fill',function (d,i) {
            if (splitValue.flag) return "green";else return "red";
        }).attr("class","order")
            .attr('fill-opacity', 0.8)
                .attr("stroke","yellow");
        chart.svg().append("text").attr('x',14).attr("y",68).text(function (d,i){
             if (splitValue.flag)  return order+1;else return "X";

        }).attr("fill","#ffeeaa").attr("class","order")
            .attr("font-size",20) ;
         if (splitValue.flag)
        {
            chart.svg().append("text").attr('x',0).attr("y",85).text("Val:"+splitValue.bestValue)
            .attr("font-size",13).attr("class","valtag");
        }
        if (splitValue.flag)
        {
            chart.svg().append("text").attr('x',0).attr("y",100).text("Mis:"+splitValue.mistake)
            .attr("font-size",13).attr("class","mistag");
        }

    }

    chart.renderCenter = function (){
        let centerlist = [];
        for (k in center) {
            centerlist.push({'index': k, 'value': center[k]});
        }
        centerlist.sort(function (a,b){return d3.ascending(a.value[feature],b.value[feature])});
        for (let i=0;i<centerlist.length;i++)
        {
            chart.body().append('circle').attr("cx",chart.scaleX(centerlist[i].value[feature])).attr("cy",-7).attr("r",5)
                .attr('fill',chart._colors[parseInt(centerlist[i].index)+1])
                .attr("stroke","black");
        }
        chart.body().append('rect').attr("id","rect2").attr("x",0).attr("y",-15).attr("width",chart.getBodyWidth()).attr("height",15)
            .style("fill","#7ba285").style("stroke","#2f2123").attr("fill-opacity",0.3);

    }

    chart.renderArea = function(){

        const areas = chart.body().insert('g')
                        .selectAll('.area')
                        .data(maxnum);

              areas.enter()
                        .append('path')
                        .attr('class', (d) => 'area area-' + d.key)
                    .merge(areas)
                        .style('fill', function(d){
                                return chart._colors[parseInt(d.key.slice(4))+1];
                        })
                  .attr('fill-opacity', 0.5)
                        .transition().duration(config.animateDuration)
                        .attrTween('d', areaTween);

        //中间帧函数
        function areaTween(_d){
            if (!_d) return;
            const generateArea = d3.area()
                        .x((d) => d[0])
                        .y0((d) => d[1])
                        .y1((d) => d[2])
                        .curve(d3.curveCardinal.tension(0));

            const pointX = data.map((d) => chart.scaleX(d.feature));
            const pointY0 = _d.map((d) => chart.scaleY(d[0]));
            const pointY1 = _d.map((d) => chart.scaleY(d[1]));

            const interpolate = getAreaInterpolate(pointX, pointY0, pointY1);

            const ponits = [];

            return function(t){
                ponits.push([interpolate.x(t), interpolate.y0(t), interpolate.y1(t)]);
                return generateArea(ponits);
            }
        }

        //点插值
        function getAreaInterpolate(pointX, pointY0, pointY1){

            const domain = d3.range(0, 1, 1/(pointX.length-1));
            domain.push(1);

            const interpolateX = d3.scaleLinear()
                                    .domain(domain)
                                    .range(pointX);

            const interpolateY0 = d3.scaleLinear()
                                    .domain(domain)
                                    .range(pointY0);

             const interpolateY1 = d3.scaleLinear()
                                    .domain(domain)
                                    .range(pointY1);
            return {
                x: interpolateX,
                y0: interpolateY0,
                y1: interpolateY1
            };

        }
        chart.body().append("line")
            .attr("id","splitline")
            .attr("x1",chart.scaleX(splitValue.bestValue))
            .attr("y1",0)
            .attr("x2",chart.scaleX(splitValue.bestValue))
            .attr("y2",80)
            .style("stroke","black").style("stroke-width",1);

    }

    /* ----------------------------渲染坐标轴------------------------  */
    chart.renderX = function(){
        chart.svg().insert('g','.body')
                .attr('transform', 'translate(' + chart.bodyX() + ',' + (chart.bodyY() + chart.getBodyHeight()) + ')')
                .attr('class', 'xAxis')
                .style("font-size",8)
                .call(d3.axisBottom(chart.scaleX).ticks(8));
    }

    chart.renderY = function(){
        chart.svg().insert('g','.body')
                .attr('transform', 'translate(' + chart.bodyX() + ',' + chart.bodyY() + ')')
                .attr('class', 'yAxis')
                .style("font-size",8)
                .call(d3.axisLeft(chart.lineScale).ticks(5));

    }

    chart.renderAxis = function(){
        chart.renderX();
        chart.renderY();
    }
    var line_generator = d3.line()
        .x(function (d,i){return chart.scaleX(d[0])})
        .y(function (d,i){return chart.lineScale(d[1])})
        .curve(d3.curveBasis);
    chart.renderLine = function ()
    {
         chart.body().append("path").attr("d",line_generator(lineData)).style("fill","none")
             .style('stroke',"black").style('stroke-width',1);

    }
    /* ----------------------------渲染文本标签------------------------  */
    chart.renderText = function(){
        d3.select('.xAxis').append('text')
                            .attr('class', 'axisText')
                            .attr('x', chart.getBodyWidth())
                            .attr('y', 0)
                            .attr('fill', config.textColor)
                            .attr('dy', 40)
                            .text('特征');

        d3.select('.yAxis').append('text')
                            .attr('class', 'axisText')
                            .attr('x', 0)
                            .attr('y', 0)
                            .attr('fill', config.textColor)
                            .attr('transform', 'rotate(-90)')
                            .attr('dy', -40)
                            .attr('text-anchor','end')
                            .text('个数）');
    }

    /* ----------------------------渲染网格线------------------------  */
    chart.renderGrid = function(){
        d3.selectAll('.xAxis .tick')
            .append('line')
            .attr('class','grid')
            .attr('stroke', config.gridColor)
            .attr('stroke-dasharray', '10,10')
            .attr('x1', 0)
            .attr('y1', 0)
            .attr('x2', 0)
            .attr('y2', -chart.getBodyHeight());
    }

    /* ----------------------------渲染图标题------------------------  */
    chart.renderTitle = function(){

chart.svg().append('text')
                .classed('title', true)
                .attr('x', chart.width()/2)
                .attr('y', 2)
                .attr('dy', '1em')
            .attr("text-anchor","middle")
                .text(featureNames[feature])
                .attr('fill', config.textColor)
                .attr('text-anchor', 'middle')
                .attr('stroke', config.textColor);
        chart.body().insert("rect",".background")
            .attr("id","rect1")
                    .attr("x",0).attr("y",0)
                    .attr("width",chart.getBodyWidth())
                    .attr("height",chart.getBodyHeight())
                     .attr("fill","#fabfee")
                    .style("fill-opacity",0);


    }

    /* ----------------------------绑定鼠标交互事件------------------------  */
    chart.addMouseOn = function(){
        //防抖函数
        function debounce(fn, time){
            let timeId = null;
            return function(){
                const context = this;
                const event = d3.event;
                timeId && clearTimeout(timeId)
                timeId = setTimeout(function(){
                    d3.event = event;
                    fn.apply(context, arguments);
                }, time);
            }
        }
        chart.svg().select(".order").on('click',function (d){

                let str = con.attr("id");
                let k =  parseInt(str.slice(10));
                let divisioncon = d3.select("#divisionView");
                drawAttributeDivisionChart(k,bestsplitValue[k],divisioncon);
        });
        chart.body().select('#rect2')
            .on('click',function (d){
                const position = d3.mouse(chart.body().node());
                let threshold = chart.scaleX.invert(position[0]).toFixed(2);
                subSet1 = [];
                subSet2 = [];
                let str = con.attr("id");
                let featureOrder =  parseInt(str.slice(10));

                for(let k in center)
                {
                    if (center[k][featureOrder]<=threshold)
                    {
                        subSet1.push(center[k]);
                    }else
                    {
                        subSet2.push(center[k]);
                    }
                }
                for (let i =0;i<splitData.length;i++)
                {
                    let sub1Max=d3.max(subSet1,(d)=>d[splitData[i].index]);
                    let sub1Min=d3.min(subSet1,(d)=>d[splitData[i].index]);
                    let sub2Max=d3.max(subSet2,(d)=>d[splitData[i].index]);
                    let sub2Min=d3.min(subSet2,(d)=>d[splitData[i].index]);
                    if(sub1Max<=sub2Min){
                         splitData[i].flag = true;
                        splitData[i].minValue = sub1Max;
                        splitData[i].maxValue = sub2Min;
                         splitData[i].mistake = d3.min(splitData[i].mistakelist,function(d,i)
                         {
                             if(d[0]<=sub1Max || d[0]>sub2Min)
                                 return null;
                             else
                                 return d[1]
                         });
                         for(let j =0 ;j<splitData[i].mistakelist.length;j++)
                        {
                            if(splitData[i].mistakelist[j][1]==splitData[i].mistake
                                && splitData[i].mistakelist[j][0]>=sub1Max
                                && splitData[i].mistakelist[j][0]<sub2Min){
                                splitData[i].bestValue = splitData[i].mistakelist[j][0];
                            }
                        }
                    }
                    else if(sub2Max<=sub1Min){
                        splitData[i].flag = true;
                        splitData[i].minValue = sub2Max;
                        splitData[i].maxValue = sub1Min;
                        splitData[i].mistake = d3.min(splitData[i].mistakelist,function(d,i)
                         {
                             if(d[0]<=sub2Max || d[0]>sub1Min)
                                 return null;
                             else
                                 return d[1]
                         });
                        for(let j =0 ;j<splitData[i].mistakelist.length;j++)
                        {
                            if(splitData[i].mistakelist[j][1]==splitData[i].mistake
                                && splitData[i].mistakelist[j][0]>=sub2Max
                                && splitData[i].mistakelist[j][0]<sub1Min){
                                splitData[i].bestValue = splitData[i].mistakelist[j][0];
                            }
                        }
                    }
                    else{
                        splitData[i].flag = false;
                        splitData[i].mistake= Infinity ;
                    }
                }
                 splitData.sort(function (a,b){
                   return  d3.ascending(a.mistake,b.mistake);
                });
                let maxmistake=0;
                for (let i = 0;i<splitData.length;i++)
                {
                    let tempmistake = d3.max(splitData,function (d,i){
                        return d3.max(d.mistakelist,function (d) {return d[1];});
                    });
                    if(tempmistake>maxmistake)
                        maxmistake=tempmistake;
                }
                d3.select("#streamView").selectAll("div").remove();
                let con1 = d3.select("#divisionView");
                let j =0;
                for (let i = 0; i < splitData.length; i++) {
                    if(featureNameImportance[splitData[i].index]) {
                        bestsplitValue[splitData[i].index] = splitData[i].bestValue;

                        let con = d3.select("#streamView").append("div").attr("id", "streamView" + splitData[i].index)
                         .style("border-bottom","2px solid #2b8f2b");

                        drawStreamChart(con, splitNode, splitData[i], maxmistake, j);
                        if (j==0)
                        {

                            drawAttributeDivisionChart(splitData[i].index,splitData[i].bestValue,con1);
                            splitTheNode();
                        }
                        j++;
                    }

                }

            });
        chart.body().select('#rect1')
            .on('mouseover', function(d){
                const e = d3.event;
                const position = d3.mouse(chart.body().node());
                e.target.style.cursor = 'hand'


                // let str = con.attr("id");
                // let k =  parseInt(str.slice(10));
                // d3.selectAll('.divisionView').style("display",'none');
                // let divisioncon = d3.select("#divisionView"+k).style("display","block");
                // drawAttributeDivisionChart(k,bestsplitValue[k],divisioncon);
                // d3.selectAll('.area')
                //     .attr('fill-opacity', 0.3);
                //
                // d3.select(e.target)
                //     .attr('fill-opacity', 1);

                // chart.svg()
                //     .append('text')
                //     .classed('tip', true)
                //     .attr('x', position[0]+5)
                //     .attr('y', position[1])
                //     .attr('fill', config.textColor)
                //     .text(chart.scaleX.invert(position[0]).toFixed(2));
            })
            .on('mouseleave', function(){
                const e = d3.event;

                // d3.selectAll('.area')
                //     .attr('fill-opacity', 1);
                //
                // d3.select('.tip').remove();
            })
            .on('mousemove', debounce(function(){
                    const position = d3.mouse(chart.body().node());

                    }, 10)
            )
            .on("click",function (inData,i){
                const position = d3.mouse(chart.body().node());
                let threshold = chart.scaleX.invert(position[0]).toFixed(2);
                let thismistake = 0;
                for(let i = 0;i<lineData.length;i++){
                    if (threshold>=lineData[i][0] && threshold<lineData[i+1][0])
                    {
                        thismistake = lineData[i][1];
                    }

                }
                chart.svg().select(".valtag").text("Val:"+threshold);
                 chart.svg().select(".mistag").text("Mis:"+thismistake);
                chart.svg().select("#splitline").attr("x1",position[0]).attr("x2",position[0]);
                let str = con.attr("id");
                let k =  parseInt(str.slice(10));
                d3.selectAll('.divisionView').style("display",'none');
                let divisioncon = d3.select("#divisionView");
                drawAttributeDivisionChart(k,threshold,divisioncon);
                splitTheNode();


            });
        // d3.selectAll('.area')
        //     .on('mouseover', function(d){
        //         const e = d3.event;
        //         const position = d3.mouse(chart.svg().node());
        //         e.target.style.cursor = 'hand'
        //
        //         d3.selectAll('.area')
        //             .attr('fill-opacity', 0.3);
        //
        //         d3.select(e.target)
        //             .attr('fill-opacity', 1);
        //
        //         chart.svg()
        //             .append('text')
        //             .classed('tip', true)
        //             .attr('x', position[0]+5)
        //             .attr('y', position[1])
        //             .attr('fill', config.textColor)
        //             .text(d.key);
        //     })
        //     .on('mouseleave', function(){
        //         const e = d3.event;
        //
        //         d3.selectAll('.area')
        //             .attr('fill-opacity', 1);
        //
        //         d3.select('.tip').remove();
        //     })
        //     .on('mousemove', debounce(function(){
        //             const position = d3.mouse(chart.svg().node());
        //             d3.select('.tip')
        //             .attr('x', position[0]+5)
        //             .attr('y', position[1]-5);
        //         }, 6)
        //     );
    }

    chart.render = function(){

        chart.renderAxis();

        // chart.renderText();

       // chart.renderGrid();



        chart.renderArea();
        chart.renderLine();
        chart.renderCenter();
        chart.renderTitle();
        chart.renderOrder ();
        chart.addMouseOn();
    }
    chart.box(con);
    chart.renderChart();


}










